/************************************************************ 
 Copyright (C), 1988-1999, Huawei Tech. Co., Ltd. 
 FileName: DCLinkList.c
 Author: GX 	Version : 1.1 	Date: 2022/2/14
 Description:
			双向循环链表的基本功能
			已经完成功能：
				创建节点	头插入	尾插入	链表拼接
				遍历输出链表所有数据	查找节点	
				删除节点	销毁链表	交换节点数据
 Version:
 Function List:
		DCLinkList *createNode(datatype data)	创建一个节点
		DCLinkList *insertHead(DCLinkList *head, datatype data)	头插入
		DCLinkList *insertTial(DCLinkList *head, datatype data)	尾插入
		bool linkCat(DCLinkList *destlink, 
					DCLinkList *src, int model)			链表拼接
		bool ergodic(DCLinkList *head, datatype model)	遍历输出整个链表数据
		bool deleteNode(DCLinkList *node)				删除节点
		bool destoryLink(DCLinkList *head)				销毁链表
		DCLinkList *searchNode(DCLinkList* head, datatype data, 
                                bool(*cmp)(datatype , datatype));	查找节点
		bool swpData(DCLinkList *pos_a, DCLinkList *pos_b)	交换节点数据

 History: // 历史修改记录
 <author> 	<time> 	<version > 	<desc> 
	GX	  2022/2/14		1.0		build this mode
	GX	  2022/2/15		1.1		delete function :
									void outputNode(DCLinkList *p)
								add function:
									bool linkCat(DCLinkList *destlink, 
										DCLinkList *src, int model)
									bool destoryLink(DCLinkList *head)
									bool swpData(DCLinkList *pos_a,
										 DCLinkList *pos_b)
	GX	  2022/2/16     1.1		modify function linkCat(...)
***********************************************************/
#include "DCLinkList.h"


/************************************************* 
 Function: DCLinkList *createNode(datatype data)
 Description:创建一个节点
 Calls: 
 Called By:	bool insertHead(DCLinkList *head, datatype data)
			bool insertTial(DCLinkList *head, datatype data)
 Input: 	datatype data	创建节点输入的数据(对象)
 Output: 
 Return:	DCLinkList *node	创建的节点地址
 Others:
*************************************************/
DCLinkList *createNode(datatype data)
{
	DCLinkList *node = malloc(sizeof(DCLinkList));
	node->prev = node->next = node;
	//node->data.num = data;
	node->data = malloc(sizeof(datatype));
	memcpy(node->data, &data, sizeof(datatype));
	return node;
}

/************************************************* 
 Function: bool insertHead(DCLinkList *head, DCLinkList *newNode)
 Description:	头插法插入一个节点
 Calls: 		DCLinkList *createNode(datatype data)
 Called By:
 Input: 		DCLinkList *head	目标链表
				DCLinkList *newNode	要插入的节点
 Output: 
 Return:		成功返回 ture 失败返回false
 Others:
*************************************************/
bool insertHead(DCLinkList *head, DCLinkList *newNode)
{
	if((head == NULL) || (newNode == NULL))
	{
		return false;
	}

	newNode->next = head->next;
	newNode->prev = head;
	head->next->prev = newNode;
	head->next = newNode;
	return true;
}

/************************************************* 
 Function: bool insertTial(DCLinkList *head, DCLinkList *newNode)
 Description:	插入到链表的尾巴
 Calls: 		DCLinkList *createNode(datatype data)
 Called By:		
 Input: 		DCLinkList *head	目标链表
				DCLinkList *newNode	要插入的节点
 Output: 
 Return:		成功返回 ture 失败返回false
 Others:
*************************************************/
bool insertTial(DCLinkList *head, DCLinkList *newNode)
{
	if((head == NULL) || (newNode == NULL))
	{
		return false;
	}

	newNode->next = head->prev->next;
	newNode->prev = head->prev;
	head->prev->next = newNode;
	head->prev = newNode;
	return true;
}

/************************************************* 
 Function: bool linkCat(DCLinkList *destlink, DCLinkList *src, int model, 
				bool (*linkCpy)(DCLinkList *, const DCLinkList))
 Description:	将链表插入到另一个链表
			拼接完后源链表会被销毁
 Calls: 	
 Called By:
 Input: 	DCLinkList *destlink    要拼接的目标链表
			DCLinkList *src			拼接源链表
									需要用户自己写显示函数
            int model               输出模式
                为0时横向输出
                为其它值时纵向输出，包含当前数据为第几个节点的信息 
 Output: 
 Return:	成功返回1， 否则返回0
 Others:	可供用户使用的接口
*************************************************/
bool linkCat(DCLinkList *destlink, DCLinkList *src, int model)
//				bool (*linkCpy)(DCLinkList *, const DCLinkList))
{
	if((destlink == NULL) || (src == NULL))
	{
		return false;
	}

	destlink->prev->next = src->next;
	src->next->prev = destlink->prev;
	src->prev->next = destlink;
	destlink->prev = src->prev;

	free(src);
	src = NULL;

	return true;

	// DCLinkList *node = src->next;/*记录节点*/
	// /*销毁源链表的方式*/
	// if(model == DestorySrc)
	// {
	// 	while(src->next != src)
	// 	{
	// 		/*1.将节点取出原链表*/
	// 		node->prev->next = node->next;
	// 		node->next->prev = node->prev;
		
	// 		/*2.将取出的节点尾插到目标链表*/
	// 		insertTial(destlink, node);

	// 		/*3.node移动准备处理src的下一个节点*/
	// 		node = src->next;
	// 	}
	// 	/*将最后的头删掉*/
	// 	deleteNode(src);
	// }
	

	return true;
}


/************************************************* 
 Function: bool ergodicLink(DCLinkList *head, void (*show)(datatype), int model)
 Description:	遍历输出整个链表的数据
 Calls: 	
 Called By:
 Input: 	DCLinkList *head     	要遍历的链表
			void (*show)(datatype)	根据用户使用的数据类型不同
									需要用户自己写显示函数
            int model               输出模式
                为0时横向输出
                为其它值时纵向输出，包含当前数据为第几个节点的信息 
 Output: 
 Return:	成功返回1， 否则返回0
 Others:	可供用户使用的接口
*************************************************/
bool ergodicLink(DCLinkList *head, void (*show)(datatype), int model)
{
	if(head == NULL)
    {
        return false;
    }

    struct DCLinkList *p = head->next;

    if(model == 0)
    {
        printf("链表数据:");
        while (p != head)
        {
           show(*p->data);
            p = p->next;
        }
        printf("\n");
    }
    else
    {
        int i = 1;
        printf("链表数据:\n");
        while (p != head)
        {
            printf("第%d个数据:     ", i++);
            show(*p->data);
            printf("\n");
            p = p->next;
        }
    }
    
    return true;
}

/************************************************* 
 Function: 	bool deleteNode(DCLinkList *node)
 Description: 删除链表中的一个节点
 Calls:     
 Called By: bool destoryLink(DCLinkList *head)
 Input:     DCLinkList *node 	需要删掉的节点
 Output: 
 Return:    成功返回 ture 失败返回false
 Others:    可供用户使用的接口
			用户一般要配合下面的查找函数使用
			DCLinkList *searchNode(DCLinkList* head, datatype data, 
									bool(*cmp)(datatype , datatype))
*************************************************/
bool deleteNode(DCLinkList *node)
{	
	if(node == NULL)
	{
			return false;
	}

  node->prev->next = node->next;
	node->next->prev = node->prev;

	free(node->data);
	free(node);
	node = NULL;
	return true;
}

/************************************************* 
 Function: bool destoryLink(DCLinkList *head)
 Description:销毁链表，销毁完头指针指向NULL
 Calls: 	bool deleteNode(DCLinkList *node)
 Called By:
 Input: 	DCLinkList *head	需要销毁的链表
 Output: 
 Return:	成功返回 ture 失败返回false
 Others:	可供用户使用的接口
*************************************************/
bool destoryLink(DCLinkList *head)
{
	if(head == NULL)
	{
		return false;
	}

	
	while(head != NULL)
	{
		DCLinkList *p = head->next;
		deleteNode(p);
		if(head == p)
		{
			head = NULL;
		}
	}
	return true;
}

/************************************************* 
 Function: 	DCLinkList *searchNode(DCLinkList* head, datatype data, bool(*cmp)(datatype , datatype))
 Description:根据数据查找到对应节点
            如果数据有重复只会找到第一个节点就退出，不会遍历整个链表
            后续会添加遍历整个链表的功能
 Calls: 
 Called By:	bool delete(DCLinkList *node)
 Input: 	DCLinkList *head    需要查找的链表
            datatype data       目标数据(对象)
			bool(*cmp)(datatype , datatype)	比较两个数据的是否相同
											根据用户使用的数据类型不同
											需要用户自己写对比函数
 Output: 	如果没有找到目标数据会向屏幕输出提示
 Return:	返回数据所在的节点指针
 Others:	可供用户使用的接口
*************************************************/
DCLinkList *searchNode(DCLinkList* head, datatype data, bool(*cmp)(datatype , datatype))
{
	if(head == NULL)
    {
        return NULL;
    }

    DCLinkList *pos = head->next;

    while(pos != head)
    {
        /*找到第一个目标数据*/
        if(cmp(*(pos->data), data))
        {
            return pos;
        }
        pos = pos->next;
    }

    printf("no found the data\n");
    return NULL;
}

/************************************************* 
 Function: bool swpData(DCLinkList *pos_a, DCLinkList *pos_b)
 Description:将两个节点的数据交换
 Calls: 
 Called By:
 Input: 	DCLinkList *pos_a	要交换数据的节点a
			DCLinkList *pos_b	要交换数据的节点b
 Output: 
 Return:	成功返回 ture 失败返回false
 Others:	可供用户使用的接口
 note:	**作者笔记**
		指针的值是一块内存的地址
		指针指向新地址和在指向的原地址赋值是不一样的概念
		下面对比两个方式
		1.赋值方式：
		int a = 0;	
		int *p = a;	//p先指向a的内存
		*p = 1;		//再给所指的内存里放东西
		2.赋值方式
		int *p = malloc(sizeof(int));	//p先指向a的内存
		memcpy(p, data, sizeof(int));	//往所指的内存里放东西
*************************************************/
bool swpData(DCLinkList *pos_a, DCLinkList *pos_b)
{
	if((pos_a == NULL) || (pos_b == NULL))
	{
		return false;
	}
	
	/*交换数据*/
	datatype *buf = malloc(sizeof(datatype)); /*创建一个临时存数据的节点*/
	memcpy(buf, pos_a->data, sizeof(datatype));
	memcpy(pos_a->data, pos_b->data, sizeof(datatype));
	memcpy(pos_b->data, buf, sizeof(datatype));

	/*清空缓存*/
	free(buf);
	buf = NULL;

	return true;
}